package tool;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import tool.analysis.series.ISeriesMember;
import tool.analysis.series.SeriesAnalyser;
import tool.csv.FileWriter;

    /**
     * @author jwb09119
     * @date 2013/12/16
     * 
     * This class is manager for a series of experiments, it ensures that parameters are reasonable
     * and runs each experiment.  The class is also responsible for ensuring that data from each 
     * experiment is available for analysis.
     *
     */


public class Workbench {

    public final static Charset ENCODING = StandardCharsets.UTF_8;
    private final static String SPEC_SOURCE_START = "@";
    private final static String SPEC_DEPENDENCY_START = "-";
    private final static String SPEC_COMMENT_START = "#";
    private File specification;
    private Map<String, List<String>> verifiedParameters;
    private Map<String, ISeriesMember> experiments;
    private SeriesAnalyser metaAnalyser;
        
    /**
     * Constructs a new Workbench object
     * @param parameters - a parameters file
     * @throws IOException - if there is some problem parsing the file
     */
    public Workbench (File parameters) throws IOException {
        
        this.specification = parameters;
        experiments = new HashMap<String, ISeriesMember>();
        
        if (parameters == null) {
           
            throw new FileNotFoundException("Unable to locate file - file specified is null!");
            
        } else if (!parameters.exists()) {
            
            throw new FileNotFoundException("Unable to locate file at " + 
                                                                     parameters.getAbsolutePath());
            
        }
        
        boolean filesOk = checkAndLoadParameters(specification);
        
        if (filesOk) {
            System.out.println("Parameters file verified");
            doExperiments(verifiedParameters);
            System.out.println("Individual experiements complete");
            
        } else {
            
            //TODO - this could be more informative!
            throw new RuntimeException("Workbench: Parameter file format not recognised");
            
        }
        
        System.out.println("Starting series analysis");
        // NB - using parameters file as 'source directory' for meta-analysis file writer
        metaAnalyser = new SeriesAnalyser(experiments, new FileWriter(parameters.toPath()));
        metaAnalyser.doSeriesAnalysis();
        System.out.println("DONE");
    }
    
    
    /**
     * Checks and loads parameters for one or more experiments
     * @param specs - a specification file
     * @return boolean - true if parameters have loaded properly, otherwise false
     */
    private final boolean checkAndLoadParameters (File specs){
        
        boolean reply = true;
        
        try {
            
            verifiedParameters = parseSpecificationFile(specs);
            
        } catch (IOException e) {
            e.printStackTrace();
            reply = false;
        }
        
        return reply;
        
    }
    
    
    private final void doExperiments (Map<String, List<String>> params) {

        for (String key : verifiedParameters.keySet()) {
            
            File target = new File(key);
            List<File> dependencies =  new ArrayList<>();
            for(String dependency : verifiedParameters.get(key)) {
                
                dependencies.add(new File(dependency));
                
            }
            
            System.out.println("Running experiment for:\n"+target+"\n\tDependents:"+dependencies);
            experiments.put(key, new Experimenter(target, dependencies));
              
        }
        
    }
    
    
    /**
     * Parses a specification file into a map of experiment targets and their dependencies
     * @param f - target specification file
     * @return - a Map of String to List of String
     * @throws IOException - if there is a problem reading the file
     */
    private final Map<String, List<String>> parseSpecificationFile (File f) throws IOException{
        
        Map<String, List<String>> reply = new HashMap<>();
        List<String> allLines;

        allLines = getAllLinesFromFile(f);
 
        String currentKey = null;
        
        for (String l : allLines){
            
            if (l.startsWith(SPEC_COMMENT_START)) {
                
                continue; // skip comments
                
            } else {
            
                if( l.startsWith(SPEC_SOURCE_START) ) {
                    
                    currentKey = l.substring(1);
                    reply.put(currentKey, new ArrayList<String>());
                    
                } else if ( l.startsWith(SPEC_DEPENDENCY_START)) {
                    
                    assert(reply.containsKey(currentKey));
                    reply.get(currentKey).add(l.substring(1));
                    
                }
                
            }
            
        }
        
        return reply;
        
    }
    
    
    /**
     * Gets all the lines from a specified file
     * @param f - the {@link File} to read
     * @return a {@link List} of {@link String}s representing the lines from the file
     * @throws IOException 
     */
    private final List<String> getAllLinesFromFile (File f) throws IOException {
        
        List<String> reply = new ArrayList<>();
            
        reply = Files.readAllLines(f.toPath(), ENCODING);
            
        return reply;
        
    }
    
    
}
